﻿using System;
using System.Collections.Concurrent;
using System.Data;
using System.Linq;

namespace Fast.Extensions.DatabaseAccessor.EntityFrameworkCore
{
    /// <summary>
    /// 数据库操作提供器
    /// </summary>
    [SkipScan]
    public static class DatabaseHelper
    {
        /// <summary>
        /// 定位器定位数据库上下文
        /// </summary>
        internal static readonly ConcurrentDictionary<Type, Type> DbContextTypeWithLocator = new ConcurrentDictionary<Type, Type>();

        /// <summary>
        /// MySql (官方)
        /// </summary>
        public const string MySQL = "MySql.EntityFrameworkCore";
        /// <summary>
        /// MySql (非官方)
        /// </summary>
        public const string MySql = "";
        /// <summary>
        /// SqlServer
        /// </summary>
        public const string SqlServer = "Microsoft.EntityFrameworkCore.SqlServer";
        /// <summary>
        /// Oracle
        /// </summary>
        public const string Oracle = "Oracle.EntityFrameworkCore";
        /// <summary>
        /// Oracle
        /// </summary>
        public const string PostgreSql = "";
        /// <summary>
        /// Sqlite
        /// </summary>
        public const string Sqlite = "Microsoft.EntityFrameworkCore.Sqlite";
        /// <summary>
        /// 内存数据库
        /// </summary>
        public const string InMemory = "Microsoft.EntityFrameworkCore.InMemory";
        /// <summary>
        /// 不支持存储过程的数据库
        /// </summary>
        internal static readonly string[] NotSupportStoredProcedureDatabases;

        static DatabaseHelper()
        {
            NotSupportStoredProcedureDatabases = new[]
            {
                Sqlite,
                InMemory
            };
        }
        /// <summary>
        /// 不支持操作类型
        /// </summary>
        private const string NotSupportException = "当前数据库不支持{0}操作.";
        /// <summary>
        /// 检查是否支持存储过程
        /// </summary>
        /// <param name="providerName">数据库提供器名词</param>
        /// <param name="commandType">命令类型</param>
        internal static void CheckStoredProcedureSupported(string providerName, CommandType commandType)
        {
            if (commandType == CommandType.StoredProcedure && NotSupportStoredProcedureDatabases.Contains(providerName))
            {
                throw new NotSupportedException(string.Format(NotSupportException, "储存过程"));
            }
        }
        /// <summary>
        /// 判断是否是特定数据库
        /// </summary>
        /// <param name="sourceName">源名字</param>
        /// <param name="targetName">目标名字</param>
        /// <returns>bool</returns>
        internal static bool IsTargetDatabase(string sourceName, string targetName)
        {
            return sourceName.Equals(targetName, StringComparison.Ordinal);
        }

        /// <summary>
        /// 添加数据库上下文和数据库上下文定位器的映射关系
        /// </summary>
        /// <param name="dbContextLocatorType"></param>
        /// <param name="dbContextType"></param>
        internal static void AddMapingOfDbContextAndDbContextLocator(Type dbContextLocatorType, Type dbContextType)
        {
            DbContextTypeWithLocator.TryAdd(dbContextLocatorType, dbContextType);
        }
        /// <summary>
        /// 添加数据库上下文和数据库上下文定位器的映射关系
        /// </summary>
        /// <param name="dbContextLocatorType"></param>
        /// <param name="dbContextType"></param>
        internal static void AddMapingOfDbContextAndDbContextLocator<TDbContextLocator, TDbContext>()
        {
            AddMapingOfDbContextAndDbContextLocator(typeof(TDbContextLocator), typeof(TDbContext));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="dbContextLocatorType"></param>
        /// <returns></returns>
        internal static Type GetDbContextByLocator(Type dbContextLocatorType)
        {
            if (!DbContextTypeWithLocator.TryGetValue(dbContextLocatorType, out var dbContextTypeWithLocator))
            {
                throw new InvalidCastException($"数据库上下文定位器{dbContextLocatorType.Name}没有绑定数据库上下文.");
            }
            return dbContextTypeWithLocator;
        }
    }
}
